package com.jinke.api.modules.third.easypost.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jinke.api.common.api.CommonResult;
import com.jinke.api.common.util.CommonUtil;
import com.jinke.api.common.util.Global;
import com.jinke.api.modules.api.conf.ApiUrlsConfig;
import com.jinke.api.modules.app.enums.BalanceLogType;
import com.jinke.api.modules.app.enums.OrderStatus;
import com.jinke.api.modules.app.enums.OrderType;
import com.jinke.api.modules.app.enums.ValidateStatus;
import com.jinke.api.modules.app.model.Order;
import com.jinke.api.modules.app.model.OrderParcel;
import com.jinke.api.modules.app.response.CreateLabel2Response;
import com.jinke.api.modules.app.service.IUserOrderTaskService;
import com.jinke.api.modules.app.service.OrderParcelService;
import com.jinke.api.modules.app.service.OrderService;
import com.jinke.api.modules.app.service.UserRechargeService;
import com.jinke.api.modules.app.util.MathUtil;
import com.jinke.api.modules.app.util.OssUtil;
import com.jinke.api.modules.base.service.ThirdService;
import com.jinke.api.modules.third.easypost.model.request.CancelInsuranceDTO;
import com.jinke.api.modules.third.easypost.model.request.GetLabelsRequest;
import com.jinke.api.modules.third.easypost.model.response.CreateInsuranceVO;
import com.jinke.api.modules.third.easypost.model.response.CreateOrderResponse;
import com.jinke.api.modules.third.easypost.model.response.GetPriceResponse;
import com.jinke.api.modules.third.easypost.service.EasyPostService;
import com.jinke.api.modules.third.easypost.util.EasypostUtil;
import com.jinke.api.modules.third.ezeeship.model.request.EstimateRateRequest;
import com.jinke.api.modules.third.ezeeship.model.response.CreateLabelResponse;
import com.jinke.api.modules.third.ezeeship.model.response.EstimateRateResponse;
import com.jinke.api.modules.third.ezeeship.service.EzeeShipService;
import com.jinke.api.modules.third.ezeeship.util.EzeeShipUtil;
import com.jinke.api.modules.ums.model.Channel;
import com.jinke.api.modules.ums.model.UmsAdmin;
import com.jinke.api.modules.ums.service.IApiLogService;
import com.jinke.api.modules.ums.service.UmsAdminService;
import com.jinke.api.modules.ums.vo.UserChannelVO;
import com.jinke.api.security.util.ApiUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.checkerframework.checker.units.qual.C;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author macro
 * @since 2024-01-13
 */
@Service
@Slf4j
public class EasypostServiceImpl implements EasyPostService {
    @Resource
    private UmsAdminService umsAdminService;
    @Resource
    private EasypostUtil easypostUtil;
    @Resource
    private OssUtil ossUtil;
    @Resource
    private EzeeShipUtil ezeeShipUtil;
    @Resource
    private OrderService orderService;

    @Resource
    private OrderParcelService orderParcelService;

    @Resource
    private UserRechargeService userRechargeService;
    @Resource
    private ThirdService thirdService;
    @Resource
    private EzeeShipService ezeeShipService;
    @Resource
    private IApiLogService iApiLogService;
    @Resource
    private IUserOrderTaskService iUserOrderTaskService;

    @Override
    public CommonResult estimateRate(EstimateRateRequest request) {
        Integer  userId = ApiUserUtil.getUserId();
        return estimateRate(request, userId);
    }

    @Override
    public CommonResult estimateRate(EstimateRateRequest request, Integer userId) {
        ezeeShipService.fillResidential(request, userId);
        UserChannelVO userChannelVO = request.getUserChannelVO();
        Channel channel = userChannelVO.getChannel();
        request.setServiceCode(channel.getChannelCode());
        BigDecimal rateAmount;
        try {
            rateAmount = getPrice(request, userId, userChannelVO);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        if (rateAmount.compareTo(new BigDecimal("0")) <= 0) {
            return CommonResult.failed("系统异常请联系管理员");
        }
        EstimateRateResponse.Data newData = new EstimateRateResponse.Data();
        newData.setRate(rateAmount);
        return CommonResult.success(newData);
    }


    private BigDecimal getPrice(EstimateRateRequest request, Integer userId, UserChannelVO vo) {
        BigDecimal rateAmount = new BigDecimal("0");
        String strResult = easypostUtil.getPrice(request);
        if (StringUtils.isNotEmpty(strResult)) {
            GetPriceResponse getPriceResponse = JSONUtil.toBean(strResult, GetPriceResponse.class);
            GetPriceResponse.GetPriceResponseDetail getPriceResponseDetail = getPriceResponse.getRates().stream()
                    .filter(x -> x.getService().equals(request.getServiceCode()))
                    .findFirst().orElse(null);
            if (ObjectUtils.isEmpty(getPriceResponseDetail)) {
                throw new RuntimeException(getPriceResponse.getMessages().get(0).getMessage());
            }
            BigDecimal price = BigDecimal.valueOf(Double.parseDouble(getPriceResponseDetail.getRate()));
            rateAmount = thirdService.calcRate(userId, vo, price);
        }
        return rateAmount;
    }

    @Override
    public CommonResult createLabel(EstimateRateRequest request) {
        Integer userId = ApiUserUtil.getUserId();
        return createLabel(request, userId);
    }


    @Override
    public CommonResult createLabel(EstimateRateRequest request, Integer userId) {
        if (StringUtils.isBlank(request.getOrderNO())) {
            request.setOrderNO(CommonUtil.getOrderNo());
        }
        ezeeShipService.fillResidential(request, userId);
        UserChannelVO userChannelVO = request.getUserChannelVO();
        UmsAdmin umsAdmin = umsAdminService.getById(userId);
        //估价
        BigDecimal rateAmount;
        try {
            rateAmount = getPrice(request, userId, userChannelVO);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        if (rateAmount.compareTo(new BigDecimal("0")) <= 0 || ObjectUtils.isEmpty(umsAdmin)) {
            return CommonResult.failed("数据异常");
        }
        List<EstimateRateRequest.Parcel> parcels = request.getParcels();
        EstimateRateRequest.Parcel parcel = parcels.get(0);
        BigDecimal calcInsurance=BigDecimal.ZERO;
        if (parcel.getIsInsured()!=null&&parcel.getInsurance()!=null) {
            //有保险计算保险费
            calcInsurance = thirdService.calcInsurance(parcel.getInsurance());
        }

        //判断用户是否有足够的金额下单
        BigDecimal totalAmount = umsAdmin.getBalance().add(umsAdmin.getCreditBalance());
        if (totalAmount.compareTo(rateAmount.add(calcInsurance)) < 0) {
            return CommonResult.failed("Insufficient Balance");
        }


        Channel channel = userChannelVO.getChannel();
        request.setServiceCode(channel.getChannelCode());
        //下单
        String strResult = easypostUtil.createOrder(request);
        if (StringUtils.isNotEmpty(strResult)) {
            CreateOrderResponse createOrderResponse = JSON.parseObject(strResult, CreateOrderResponse.class);
            Order order = new Order();
            BeanUtils.copyProperties(request, order);
            order.setId(request.getOrderId());
            if (createOrderResponse.toCommonResult().isSucess()) {
                order.setUserId(userId);
                //设置错误信息为空
                order.setErrMsg("");
                order.setOrderNo(request.getOrderNO());
                if (ObjectUtils.isNotEmpty(umsAdmin.getSellerId())) {
                    order.setSellerId(umsAdmin.getSellerId());
                }
                CreateOrderResponse.GetPriceResponseDetail selectedRate = createOrderResponse.getSelectedRate();


                BigDecimal rate = BigDecimal.valueOf(Double.parseDouble(selectedRate.getRate()));
                //计算要扣的钱
                BigDecimal afterRate = thirdService.calcRate(userId, request.getUserChannelVO(), rate);

                order.setRate(afterRate);
                order.setOriginFee(rate);
                //三方的标识取消用
                String objectId = createOrderResponse.getId();

                String trackingCode = createOrderResponse.getTrackingCode();
                CancelInsuranceDTO insuranceDto=null;
                //有保险要计算
                if (parcel.getIsInsured()!=null&&parcel.getInsurance()!=null) {
                    insuranceDto=new CancelInsuranceDTO();
                    //第三方收我们的保险费
                    BigDecimal insuranceFeeAmount = createOrderResponse.findInsuranceFeeAmount();
                    //加点后的保险费
                    BigDecimal calcInsurance1 = thirdService.calcInsurance(insuranceFeeAmount);
                    insuranceDto.setInsurance(calcInsurance1);
                    insuranceDto.setId(objectId);
                }


                //扣钱是否成功
                boolean decrTransfer = true;
                // 扣钱  加一个条件
                BigDecimal finalRate = afterRate;
                if (finalRate != null && BigDecimal.ZERO.compareTo(finalRate) < 0) {
                    decrTransfer = userRechargeService.decrTransfer(userId, finalRate, BalanceLogType.CONSUME, "寄件", order.getOrderNo(), objectId, channel,insuranceDto);
                }


                if (decrTransfer) {

                    GetLabelsRequest getLabelsRequest = new GetLabelsRequest();
                    getLabelsRequest.setPlatformNo(objectId);
                    String localFilePath = pngToPdf(createOrderResponse.getPostageLabel().getLabelUrl(), objectId);

                    // 上传到oss
                    ossUtil.uploadLocal("pdf", objectId + ".pdf", localFilePath);

                    String newPdfUrl = Global.PRINT_LABEL_API + objectId;
                    // order.setCreateTime(LocalDateTime.now());

                    try {
                        order.setReference(request.getExtra().getReference());
                        order.setReference2(request.getExtra().getReference2());
                    } catch (Exception e) {
                        log.error("设置reference出错了");
                    }

                    order.setFromCity(request.getFrom().getCity());
                    order.setFromEmail(request.getFrom().getEmail());
                    order.setFromCompany(request.getFrom().getCompany());
                    order.setFromPhone(request.getFrom().getPhone());
                    order.setFromAddressLine2(request.getFrom().getAddressLine2());
                    order.setFromAddressLine1(request.getFrom().getAddressLine1());
                    order.setFromCountryCode(request.getFrom().getCountryCode());
                    order.setFromZipCode(request.getFrom().getZipCode());
                    order.setFromPersonName(request.getFrom().getPersonName());
                    order.setFromStateCode(request.getFrom().getStateCode());

                    EstimateRateRequest.Address requestTo = request.getTo();
                    order.setToCity(requestTo.getCity());
                    order.setToEmail(requestTo.getEmail());
                    order.setToCompany(requestTo.getCompany());
                    order.setToPhone(requestTo.getPhone());
                    order.setToAddressLine2(requestTo.getAddressLine2());
                    order.setToAddressLine1(requestTo.getAddressLine1());
                    order.setToCountryCode(requestTo.getCountryCode());
                    order.setToZipCode(requestTo.getZipCode());
                    order.setToPersonName(requestTo.getPersonName());
                    order.setToStateCode(requestTo.getStateCode());
                    order.setOrderType(request.getOrderType());

                    order.setPdfUrl(newPdfUrl);
                    order.setStatus(OrderStatus.RECENT.getValue());
                    order.setObjectId(objectId);

                    if (BooleanUtil.isTrue(requestTo.getIsValid())) {
                        order.setValidateStatus(ValidateStatus.defaultEnum(requestTo.getIsResidential()));
                    } else {
                        order.setValidateStatus(ValidateStatus.UN_VALIDATE);
                    }
                    order.setCreateTime(LocalDateTime.now());

                    // 保证金
                    BigDecimal earnestRate = umsAdmin.getEarnestRate();
                    BigDecimal subEarnestBalance = MathUtil.formatBigDecimal(afterRate.multiply(earnestRate));
                    order.setEarnest(subEarnestBalance);
                    //保存订单信息
                    orderService.saveOrUpdate(order);
                    //定时任务表插入一条数据
                    iUserOrderTaskService.saveByOrderId(order.getId());

                    Integer orderId = order.getId();

                    //更新包裹
                    updateParcel(request, userId, newPdfUrl, orderId, trackingCode);

                    //组装返回
                    CreateLabelResponse.Data newCreateLabelResponseData = getCreateLabelReturn(objectId, finalRate, newPdfUrl, trackingCode);

                    return CommonResult.success(newCreateLabelResponseData);
                }
                else {
                    //取消订单
                    return CommonResult.failed("Insufficient Balance");
                }

            } else {
                String message = createOrderResponse.toCommonResult().getMessage().replaceAll("接口返回：：", "");
                message = ezeeShipUtil.fmtMsg(message);
                if (order.getId() != null) {
                    orderService.update(new LambdaUpdateWrapper<Order>().eq(Order::getId, order.getId()).set(Order::getErrMsg, message));
                }
                return CommonResult.failed(message);
            }
        }
        return CommonResult.failed("下单失败！！！");
    }

    /**
     * 组装返回
     * @param objectId
     * @param finalRate
     * @param newPdfUrl
     * @param trackingCode
     * @return
     */
    @NotNull
    private CreateLabelResponse.Data getCreateLabelReturn(String objectId, BigDecimal finalRate, String newPdfUrl, String trackingCode) {
        CreateLabelResponse.Data newCreateLabelResponseData = new CreateLabelResponse.Data();
        newCreateLabelResponseData.setRate(finalRate);

        CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
        newFeeDetail.setBaseRate(finalRate);
        newCreateLabelResponseData.setFeeDetail(newFeeDetail);

        newCreateLabelResponseData.setRate(finalRate);
        newCreateLabelResponseData.setStatus(1);
        newCreateLabelResponseData.setCreateTime(LocalDateTime.now());
        newCreateLabelResponseData.setObjectId(objectId);
        newCreateLabelResponseData.setPdfUrl(newPdfUrl);
        newCreateLabelResponseData.setTrackingNumber(Arrays.asList(trackingCode));
        String labelUrl = Global.PRINT_LABEL_API + objectId;
        newCreateLabelResponseData.setLabelUrl(Arrays.asList(labelUrl));
        return newCreateLabelResponseData;
    }

    /**
     * 更新包裹
     * @param request
     * @param userId
     * @param newPdfUrl
     * @param orderId
     * @param trackingCode
     * @param calcInsurance1
     */
    @Transactional
    void updateParcel(EstimateRateRequest request, Integer userId, String newPdfUrl, Integer orderId, String trackingCode) {
        List<EstimateRateRequest.Parcel> parcels = request.getParcels();
        List<OrderParcel> orderParcels = parcels.stream().map(x -> {
            OrderParcel orderParcel = new OrderParcel();
            orderParcel.setOrderId(orderId);
            orderParcel.setUserId(userId);
            BeanUtils.copyProperties(x, orderParcel);
            EstimateRateRequest.Extra extra = x.getExtra();
            if (extra != null) {
                BeanUtils.copyProperties(extra, orderParcel);
            }

            //保险保价申报额
            try {
                orderParcel.setInsurance(x.getInsurance());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return orderParcel;
        }).collect(Collectors.toList());
        // 入库
        orderParcelService.remove(new LambdaQueryWrapper<OrderParcel>().eq(OrderParcel::getOrderId, orderId));
        for (int i = 0; i < orderParcels.size(); i++) {
            orderParcels.get(i).setTrackingNumber(trackingCode);
            // orderParcels.get(i).setTrackingUrl(createLabelResponseData.getTrackingUrl().get(i));
            orderParcels.get(i).setLabelUrl(newPdfUrl);
        }
        orderParcelService.saveBatch(orderParcels);
    }

    private static String pngToPdf(String imgUrl, String id) {
        PDDocument document = new PDDocument();
        PDPage page = new PDPage(PDRectangle.A6);
        document.addPage(page);

        String fileName = id + ".pdf";
        String tempDir = System.getProperty("java.io.tmpdir");
        String localFilePath = tempDir + File.separator + fileName;
        try {
            // 加载PNG图像
            URL url = new URL(imgUrl);
            BufferedImage bufferedImage = ImageIO.read(url);

            // 将PNG图片写入ByteArrayOutputStream
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", baos);

            // 将ByteArrayOutputStream中的数据转换为字节数组
            byte[] imageBytes = baos.toByteArray();
            baos.close();
            PDImageXObject image = PDImageXObject.createFromByteArray(document, imageBytes, "png");

            // 将PNG图像添加到PDF页面
            PDPageContentStream contentStream = new PDPageContentStream(document, page);
            contentStream.drawImage(image, 0, 0, PDRectangle.A6.getWidth(), PDRectangle.A6.getHeight());
            contentStream.close();

            // 保存PDF文件
            document.save(localFilePath);
            document.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return localFilePath;
    }

    @Override
    public CommonResult getLabel(String objectId) {

        return getLabel(objectId, null);

    }

    @Override
    public CommonResult getLabel(String objectId, Integer userId) {
        log.info(JSONUtil.toJsonStr(objectId));
        GetLabelsRequest getLabelsRequest = new GetLabelsRequest();
        getLabelsRequest.setPlatformNo(objectId);
        CreateLabelResponse.Data createLabelResponseData = new CreateLabelResponse.Data();

        if (userId == null) {
            userId = ApiUserUtil.getUserId();
        }
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getObjectId, objectId)
                .eq(Order::getUserId, userId)
        );

        if (order == null) {
            return CommonResult.success(createLabelResponseData);
        }

        CreateLabelResponse.Data newCreateLabelResponseData = new CreateLabelResponse.Data();
        newCreateLabelResponseData.setObjectId(objectId);
        newCreateLabelResponseData.setPdfUrl(order.getPdfUrl());
        BigDecimal finalRate = order.getRate();
        newCreateLabelResponseData.setRate(finalRate);
        newCreateLabelResponseData.setStatus(createLabelResponseData.getStatus());
        CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
        newFeeDetail.setBaseRate(finalRate);
        newCreateLabelResponseData.setFeeDetail(newFeeDetail);

        newCreateLabelResponseData.setCreateTime(createLabelResponseData.getCreateTime());
        newCreateLabelResponseData.setTrackingNumber(createLabelResponseData.getTrackingNumber());

        String labelUrl = Global.PRINT_LABEL_API + objectId;
        newCreateLabelResponseData.setLabelUrl(Arrays.asList(labelUrl));
        return CommonResult.success(newCreateLabelResponseData);

    }

    @Override
    public CommonResult cancelLabel(String objectId,String orderNo) {
        String strResult = easypostUtil.cancelLabel(objectId,orderNo);
        if (StringUtils.isNotBlank(strResult)) {
            CreateOrderResponse createLabelResponse = JSONUtil.toBean(strResult, CreateOrderResponse.class);
            if (!createLabelResponse.isSuccess()) {
                return CommonResult.failed();
            }
        }
        return CommonResult.success();
    }

    @Override
    public CommonResult tracking(String trackingNumber) {
        return CommonResult.success();
    }

    @Override
    public CommonResult cancelInsurance(String insuranceId) {
        String strResult = easypostUtil.refundInsurances(insuranceId,"ins");
        if (StringUtils.isNotBlank(strResult)) {
            CreateOrderResponse createLabelResponse = JSONUtil.toBean(strResult, CreateOrderResponse.class);
            if (!createLabelResponse.isSuccess()) {

                return CommonResult.failed();
            }
        }
        return CommonResult.success();
    }


}
